package com.xuecheng.publish.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.common.constant.CoursePubTemplateKey;
import com.xuecheng.common.enums.content.CourseModeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.JsonUtil;
import com.xuecheng.publish.common.constant.CoursePublishErrorCode;
import com.xuecheng.publish.common.util.QiniuUtils;
import com.xuecheng.publish.entity.CourseMarket;
import com.xuecheng.publish.entity.CoursePub;
import com.xuecheng.publish.entity.CoursePubMsg;
import com.xuecheng.publish.mapper.CoursePubMapper;
import com.xuecheng.publish.service.CoursePubService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 课程发布 服务实现类
 * </p>
 *
 * @author dongliang
 */
@Slf4j
@Service
public class CoursePubServiceImpl extends ServiceImpl<CoursePubMapper, CoursePub> implements CoursePubService {

    @Autowired
    private Configuration configuration;

    /*

    #生成静态化页面发布位置
    course.publish.position = pages/
    #七牛云的存储消息
    file.qiniu.accessKey = pFcOu02W6CdSqjY6qmRH1jz--pwfQEVyuM4RkBGC
    file.qiniu.secretKey = z4CqmQb9LYD3AiuViX3ADk3r3-iOAm9yQePGP6Hh
    file.qiniu.bucket = xc134-staitc-pages
        * */

    @Value("${file.qiniu.accessKey}")
    private String accessKey;

    @Value("${file.qiniu.secretKey}")
    private String secretKey;

    @Value("${file.qiniu.bucket}")
    private String bucket;

    @Value("${course.publish.position}")
    private String position;

    /*
     * 业务分析：
     *   1.实现消息的幂等性
     *       跟coursePubId  isPub
     *       查询CoursePub表
     *   2.生成课程页面
     *       数据模型-通过CoursePub
     *       页面模板-通过Configuration
     *           无需创建，Spring-boot-starter-Freemarker已经将Configuration对象创建出来
     *
     *   3.将页面上传到cdn服务上
     *   4.修改课程发布状态is_pub
     *
     * */
    /**
     * 课程发布_消费方
     * @param coursePubMsg 课程发布msg
     */
    @Transactional
    public void publishPage(CoursePubMsg coursePubMsg) {

        // 1.实现消息的幂等性
        //      跟coursePubId  isPub--mysql
        //      查询CoursePub表
        //  判断课程发布有没有操作完--发布页面
        LambdaQueryWrapper<CoursePub> pubQueryWrapper = new LambdaQueryWrapper<>();
        pubQueryWrapper.eq(CoursePub::getId, coursePubMsg.getPubId());
        pubQueryWrapper.eq(CoursePub::getIsPub, CoursePub.IS_PUB);

        int count = this.count(pubQueryWrapper);

        // 如果消息已经发布并将页面上传到cdn中，无需抛出异常，只需要记录操作信息
        if (count > 0) {
            log.info("课程发布消息已经产生页面，无需操作，课程id："+coursePubMsg.getPubId());
            return;
        }


        //  2.生成课程页面
        //      数据模型-通过CoursePub
        //      页面模板-通过Configuration
        //          无需创建，Spring-boot-starter-Freemarker已经将Configuration对象创建出来
        Long pubId = coursePubMsg.getPubId();
        CoursePub coursePub = this.getById(pubId);

        if (ObjectUtils.isEmpty(coursePub)) {
            ExceptionCast.cast(CoursePublishErrorCode.E_120203);
        }

        String html = null;
        try {
            Map<String, Object> dataMap = generateDataMap(coursePub);

            Template template = configuration.getTemplate("learing_article.ftl");

            html = FreeMarkerTemplateUtils.processTemplateIntoString(template, dataMap);
        } catch (Exception e) {
            log.error("课程生成详情页失败，coursePub：{}",coursePubMsg.getPubId());
            ExceptionCast.cast(CoursePublishErrorCode.E_120209);
        }


        //  3.将页面上传到cdn服务上

        // html名称：coursePubId.html
        // cdn上：pages/页面
        try {
            String fileKey = position+coursePubMsg.getPubId()+".html";

            QiniuUtils.upload2Qiniu(accessKey, secretKey, bucket, html, fileKey);
        } catch (Exception e) {
            log.error("课程详情页上传cdn失败，coursePub：{}",coursePubMsg.getPubId());
            ExceptionCast.cast(CoursePublishErrorCode.E_120210);
        }


        //  4.修改课程发布状态is_pub
        LambdaUpdateWrapper<CoursePub> pubUpdateWrapper = new LambdaUpdateWrapper<>();
        pubUpdateWrapper.set(CoursePub::getIsPub, CoursePub.IS_PUB);
        pubUpdateWrapper.set(CoursePub::getChangeDate, LocalDateTime.now());
        pubUpdateWrapper.eq(CoursePub::getId, coursePubMsg.getPubId());

        boolean result = this.update(pubUpdateWrapper);

        if (!result) {
            ExceptionCast.cast(CoursePublishErrorCode.E_120212);
        }

    }


    //生成dataMap模板数据
    private Map<String, Object> generateDataMap(CoursePub coursepub) {

        // 1.声明数据模型DataMap
        HashMap<String, Object> dataMap = new HashMap<>();

        // 课程发布数据
        dataMap.put(CoursePubTemplateKey.COURSEPUB, coursepub);


        String marketJsonString = coursepub.getMarket();
        CourseMarket courseMarket = JsonUtil.jsonToObject(marketJsonString, CourseMarket.class);

        // 课程营销数据
        dataMap.put(CoursePubTemplateKey.COURSEMARKET, courseMarket);


        // 课程模式枚举数据
        CourseModeEnum[] values = CourseModeEnum.values();
        dataMap.put(CoursePubTemplateKey.COURSETEACHMODEENUMS, values);


        // 课程计划数据
        String teachplanJsonString = coursepub.getTeachplan();

        TeachplanDTO teachplanDTO = JsonUtil.jsonToObject(teachplanJsonString, TeachplanDTO.class);
        dataMap.put(CoursePubTemplateKey.TEACHPLANNODE, teachplanDTO);

        return dataMap;
    }

}